package org.qiuer.ast.expression;

import org.qiuer.func.AMemberFunction;
import org.qiuer.func.ANormalFunction;
import org.qiuer.run.Context;
import org.qiuer.run.FunctionRegistrar;
import org.qiuer.exception.*;

import java.util.ArrayList;
import java.util.List;

public class CallExpression extends Expression {
  public String type = "CallExpression";
  public IExpression callee;
  public List<IExpression> arguments = new ArrayList<>();//调用参数

  // 内置属性

  public CallExpression(){}
  public CallExpression(IExpression callee, List<IExpression> arguments){
    this.callee = callee;
    this.arguments = arguments;
  }

  @Override
  public void compile() throws IException {
    EValidate.notNull(callee);
  }

  @Override
  public Object run(Context context) throws IException {
    context.enterScope();
    try {
      AMemberFunction memberFunc = null;
      Object memberFuncObj = null;
      ANormalFunction normalFunc = null;
      String functionName;
      if (callee instanceof MemberExpression) {
        MemberExpression calleeMember = (MemberExpression) callee;
        memberFuncObj = calleeMember.object.run(context);
        if (((MemberExpression) callee).property instanceof Identifier) {
          functionName = ((Identifier) ((MemberExpression) callee).property).name;
        } else
          throw new ERuntime(Const.EXCEPTION.UNSUPPORTED_OPERATION, "成员函数调用的函数名只能是标识符类型");
        memberFunc = FunctionRegistrar.getMemberFunction(memberFuncObj.getClass(), functionName);

      } else if (callee instanceof Identifier) {
        functionName = ((Identifier) callee).name;
        normalFunc = FunctionRegistrar.getNormalFunction(functionName);
        if (normalFunc == null){
          Object obj = context.getVariableValue(functionName);
          if (obj instanceof ANormalFunction){
            normalFunc = (ANormalFunction) obj;
          }
        }
      } //else if (callee instanceof Function) f = (Function) callee;
      else throw new ERuntime(Const.EXCEPTION.UNSUPPORTED_OPERATION, "函数调用只支持标识符和成员函数调用");
      EValidate.assertTrue(memberFunc != null || normalFunc != null, "未找到函数" + functionName);
      if (normalFunc != null){
        return normalFunc.run(context, arguments);
      }else {
        return memberFunc.run(memberFuncObj, context, arguments);
      }
    }catch (EReturn eReturn){
      return eReturn.getObject();
    }catch (IException e) {
      throw e;
    } catch (Exception e) {
      e.printStackTrace();
      throw new ERuntime(Const.EXCEPTION.UNKNOWN_ERROR, e.getMessage());
    }finally {
      context.exitScope();
    }
  }

}
